import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';

class UnifyScrollController extends ScrollController {
  @override
  _UnifyScrollPosition createScrollPosition(ScrollPhysics physics,
      ScrollContext context, ScrollPosition? oldPosition) {
    return _UnifyScrollPosition(
      this,
      physics: physics,
      context: context,
      initialPixels: initialScrollOffset,
      oldPosition: oldPosition,
    );
  }

  // ignore: non_constant_identifier_names
  double _p_initialScrollOffset = 0;

  @override
  double get initialScrollOffset => _p_initialScrollOffset;

  @override
  ScrollPosition get position => positions.first;
}

class _UnifyScrollPosition extends ScrollPositionWithSingleContext {
  _UnifyScrollPosition(
    this.owner, {
    required ScrollPhysics physics,
    required ScrollContext context,
    required double initialPixels,
    ScrollPosition? oldPosition,
  }) : super(
          physics: physics,
          context: context,
          initialPixels: initialPixels,
          oldPosition: oldPosition,
        );

  final UnifyScrollController owner;

  @override
  double setPixels(double newPixels) {
    if (newPixels == pixels) {
      return 0.0;
    }
    if (owner._p_initialScrollOffset != newPixels) {
      owner._p_initialScrollOffset = newPixels;
    }
    updateUserScrollDirection(newPixels - pixels > 0.0
        ? ScrollDirection.forward
        : ScrollDirection.reverse);

    // ignore: invalid_use_of_protected_member
    for (var position in owner.positions) {
      if (position != this && position is _UnifyScrollPosition) {
        position.beginActivity(_UnifyScrollActivity(position));
        position.setPixelsInternal(newPixels);
      }
    }

    return setPixelsInternal(newPixels);
  }

  double setPixelsInternal(double newPixels) {
    return super.setPixels(newPixels);
  }
}

class _UnifyScrollActivity extends ScrollActivity {
  _UnifyScrollActivity(ScrollActivityDelegate delegate) : super(delegate);

  @override
  bool get isScrolling => true;

  @override
  bool get shouldIgnorePointer => true;

  @override
  double get velocity => 0.0;
}
